package team.seekers.hula.question.point.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import team.seekers.hula.common.entity.VisibilityUpdateDTO;
import team.seekers.hula.common.entity.constant.IdConstant;
import team.seekers.hula.common.entity.enums.MessageTypeEnum;
import team.seekers.hula.common.entity.enums.question.PointOrderEnum;
import team.seekers.hula.common.entity.enums.StatusEnum;
import team.seekers.hula.auth.service.MindUtils;
import team.seekers.hula.question.answer.service.AnswerService;
import team.seekers.hula.record.mind.service.MindService;
import team.seekers.hula.message.message.service.MessageService;
import team.seekers.hula.question.question.service.QuestionService;
import team.seekers.hula.question.answer.entity.dto.AnswerAddDTO;
import team.seekers.hula.question.point.entity.dto.PointAddDTO;
import team.seekers.hula.question.point.entity.vo.PointInfoVO;
import team.seekers.hula.question.answer.entity.dao.AnswerDO;
import team.seekers.hula.question.point.entity.dao.PointDO;
import team.seekers.hula.message.message.entity.dao.MessageDO;
import team.seekers.hula.question.point.entity.vo.PointListVO;
import team.seekers.hula.question.point.entity.dto.PointUpdateDTO;
import team.seekers.hula.question.point.mapper.PointMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import team.seekers.hula.user.user.entity.dao.UserDO;
import team.seekers.hula.user.user.service.UserService;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 关于问题的一个观点 服务实现类
 * @author hbc
 * @since 2021-02-15
 */
@Service
public class PointService extends ServiceImpl<PointMapper, PointDO> {

    @Autowired
    private UserService userService;

    @Autowired
    private MindService mindService;

    @Autowired
    private AnswerService answerService;

    @Autowired
    private QuestionService questionService;

    @Autowired
    private MessageService messageService;

    @Transactional(rollbackFor=Exception.class)
    public String add(PointAddDTO pointAddDTO) {
        PointDO pointDO = new PointDO();
        // 新增观点
        BeanUtils.copyProperties(pointAddDTO, pointDO);
        pointDO.setUserId(MindUtils.getUserId());
        pointDO.setStatus(StatusEnum.WAIT);
        save(pointDO);


        // TODO 敏感词筛查（包扩附带的一个回答）

        // 通知审核
        MessageDO messageDO = new MessageDO();
        messageDO.setQuestionId(pointAddDTO.getQuestionId());
        messageDO.setLinkId(pointDO.getId());
        messageDO.setFromId(MindUtils.getUserId());
        messageDO.setType(MessageTypeEnum.POINT);
        if(questionService.isSpecial(pointAddDTO.getQuestionId())){
            // 专业提问，通知提问者和暗流审核观点
            messageDO.setToId(IdConstant.superAdmin);
        }else {
            // 普通提问，通知提问者审核观点
            messageDO.setToId(IdConstant.superAdmin);
        }
        messageService.save(messageDO);


        // 新增回答
        AnswerDO answerDO = new AnswerDO();
        AnswerAddDTO answerAddDTO = pointAddDTO.getAnswerAddDTO();
        BeanUtils.copyProperties(answerAddDTO, answerDO);
        answerDO.setQuestionId(pointDO.getQuestionId());
        answerDO.setPointId(pointDO.getId());
        answerDO.setUserId(MindUtils.getUserId());
        answerDO.setStatus(StatusEnum.PASS);
        answerService.save(answerDO);

        // TODO 设定用户关注问题并维护关注数据

        // 维护mind记录
        mindService.addPoint(pointDO.getId(),pointDO.getVisibility());
        return pointDO.getId();
    }


    public void delete(String pointId) {
        PointDO pointDO = getById(pointId);
        // 是观点的提出者在没有回答了的情况下
        if(pointDO.getUserId().equals(MindUtils.getUserId()) && answerService.getAnswerCountByPointId(pointId) == 0){

            // 维护mind表
            mindService.deleteMindByLinkId(pointId);

            // 删除观点
            removeById(pointId);
        }
    }


    public void updateInfo(PointUpdateDTO updateVO) {
        PointDO pointDO = getById(updateVO.getId());
        //判断是不是自己的观点
        if(pointDO.getUserId().equals(MindUtils.getUserId())){
            BeanUtils.copyProperties(updateVO, pointDO);
            updateById(pointDO);
        }
    }

    public void updateVisibility(VisibilityUpdateDTO updateDTO) {
        lambdaUpdate().set(PointDO::getVisibility,updateDTO.getVisibility())
                .eq(PointDO::getId,updateDTO.getId())
                .update();

        mindService.updateVisibilityByLinkId(updateDTO.getId(),updateDTO.getVisibility());
    }

    public PointInfoVO getInfoVO(String id) {
        PointInfoVO infoVO = new PointInfoVO();
        PointDO pointDO = getById(id);
        BeanUtils.copyProperties(pointDO,infoVO);


        infoVO.setUserInfo(userService.getFollowInfoVO(pointDO.getUserId(),MindUtils.getUserId()));
        infoVO.setIsMine(MindUtils.getUserId().equals(pointDO.getUserId()));
        return infoVO;
    }


    public List<PointListVO> list(String questionId, PointOrderEnum orderEnum) {
        LambdaQueryChainWrapper<PointDO> wrapper = lambdaQuery().eq(PointDO::getQuestionId, questionId);

        switch (orderEnum){
            case NEW:
                wrapper.orderByDesc(PointDO::getGmtCreate);
                break;
            case DEFAULT:
                wrapper.orderByDesc(PointDO::getHeat);
                break;
            case FIRE:
                // 更新该问题所有观点的热度
                updatePointsHeatByQuestionId(questionId);
                wrapper.orderByDesc(PointDO::getFire);
                break;
            case ME:
                wrapper.orderByDesc(PointDO::getFire);
                wrapper.eq(PointDO::getUserId,MindUtils.getUserId());
                break;
        }

        List<PointDO> list = wrapper.list();

        return toListVOList(list);
    }

    public List<PointListVO> listTwo(String questionId) {
        List<PointDO> list = lambdaQuery()
                .eq(PointDO::getQuestionId, questionId)
                .last("limit 2")
                .list();
        return toListVOList(list);
    }

    private  List<PointListVO> toListVOList(List<PointDO> list){
        if(list.size() == 0){
            return new ArrayList<>();
        }
        List<PointListVO> pointListVOList = new ArrayList<>();
        for (PointDO pointDO : list) {
            PointListVO pointListVO = new PointListVO();
            BeanUtils.copyProperties(pointDO,pointListVO);
            UserDO userDO = userService.getById(pointDO.getUserId());
            if(MindUtils.isLogin() && pointDO.getUserId().equals(MindUtils.getUserId())){
                pointListVO.setIsMe(true);
            }
            pointListVO.setAnswerCount(answerService.getAnswerCountByPointId(pointDO.getId()));
            pointListVO.setNickname(userDO.getNickname());
            pointListVO.setAvatar(userDO.getAvatar());
            pointListVO.setUserId(userDO.getId());
            pointListVOList.add(pointListVO);
        }
        return pointListVOList;
    }


    // 数据变化
    public void addFire(String pointId, Integer fire) {
        PointDO pointDO = lambdaQuery().select(
                PointDO::getId,
                PointDO::getFire
        ).eq(PointDO::getId, pointId).one();

        pointDO.setFire(pointDO.getFire()+fire);
        updateById(pointDO);
    }



    //更新所有字段的heat值
    @Transactional(rollbackFor=Exception.class)
    public void updatePointsHeatByQuestionId(String questionId){
        Date now=new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date currentDate = sdf.parse(sdf.format(now));
            QueryWrapper<PointDO> wrapper = new QueryWrapper<>();
            wrapper.eq("question_id",questionId);
            List<PointDO> pointDOList = baseMapper.selectList(wrapper);
            for(PointDO pointDO : pointDOList){
                String v = setPointHot(pointDO, currentDate);
                pointDO.setHeat(v);
                baseMapper.updateById(pointDO);
            }
        } catch (ParseException e){
            e.printStackTrace();
        }
    }

    //热度排行算法
    public String setPointHot(PointDO pointDO, Date currentDate) {
        Integer answerNumber = answerService.getAnswerCountByPointId(pointDO.getId());
        Integer goodNumber = pointDO.getFire();
        Date gmtCreate = pointDO.getGmtCreate();
        float v = MindUtils.differentDaysByMillisecond(gmtCreate, currentDate);
        double heat = (goodNumber*3+answerNumber*5+1) / Math.pow((v + 2), 1.8);
        return heat+"";
    }

    public String getPointKeyword(String pointId) {
        return lambdaQuery().select(PointDO::getKeyword).eq(PointDO::getId,pointId).one().getKeyword();
    }

    public Integer countByQuestionId(String questionId) {
        return lambdaQuery().eq(PointDO::getQuestionId,questionId).count();
    }
}
